#include "cms_common.h"
#include "cms_log.h"
#include "core_utils.h"
#include "libmdm.h"
#include "cms_utils.h"


cms_moduleList_t *moduleList = NULL;
cms_eventList_t  *eventList = NULL;
cmsXmlCb_t *cmsXmlCb = NULL, *cmsDefXmlCb = NULL;
extern int cmsModuleId;


/*check process is exist, if not exist or dead, del from list and release msg queue*/
static void cmsCore_moduleCheck(void)
{
	cms_moduleList_t *pCurModule = NULL, *pTmpModule = NULL;
	char cmdStr[24] = {0};
	uint32_t appPid = 0;
	uint32_t moduleMId;
	uint32_t eventMId;

	pCurModule = moduleList;
	while(pCurModule){
		appPid = pCurModule->module->moduleInfo.pid;
		moduleMId = pCurModule->module->moduleInfo.moduleMsqId;
		eventMId = pCurModule->module->moduleInfo.eventMsqId;
		memset(cmdStr, 0, 24);

		if(!strstr(pCurModule->module->moduleInfo.moduleName, ".cgi")){//only support cgi check now
			pCurModule = pCurModule->next;
			continue;
		}
		
		msgctl(moduleMId, IPC_RMID, NULL);
		msgctl(eventMId, IPC_RMID, NULL);
		sprintf(cmdStr, "kill -9 %d", appPid);
		cms_do_cmd(cmdStr);
		pTmpModule = pCurModule;
		
		pCurModule = pCurModule->next;

		if(pTmpModule){
			DELETE_NODE(moduleList, pTmpModule);
			pTmpModule = NULL;
		}
	}
}

static int cmsCore_Init(void){
	cms_module_t *pCoreModule = NULL;
	cms_moduleList_t *pCurModuleList = NULL;
	int coreMKey = -1, coreEKey = -1;
	char *defaultXmlPath = NULL;
	char cmdStr[128] = {0};

	CMS_LOG(LL_PRINT|LL_SYSLOG, "cms_core init");
	
	/*init cms_core module*/
	pCoreModule = (cms_module_t *)calloc(1, sizeof(cms_module_t));
	if(pCoreModule == NULL){
		CMS_LOG(LL_ERROR, "core init fail, malloc module fail.\n");
		return -1;
	}

	/*get cms_core moduleidKey & eventidKey*/
	genKeyByName(CMS_CORE, &coreMKey, &coreEKey);

	/*get cms_core message queue id by key*/
	pCoreModule->moduleInfo.moduleMsqId = msgget(coreMKey, 0666);
	CMS_LOG(LL_INFO, "shmget success, modulemsqId %d, key 0x%x.\n", pCoreModule->moduleInfo.moduleMsqId, coreMKey);
	if(pCoreModule->moduleInfo.moduleMsqId == -1){
		pCoreModule->moduleInfo.moduleMsqId = msgget(coreMKey, 0666 | IPC_CREAT);
		CMS_LOG(LL_INFO, "shmget success, modulemsqId %d, key 0x%x.\n", pCoreModule->moduleInfo.moduleMsqId, coreMKey);
	}
	cmsModuleId = pCoreModule->moduleInfo.moduleMsqId;
	
	pCoreModule->moduleInfo.eventMsqId = msgget(coreEKey, 0666);
	CMS_LOG(LL_INFO, "shmget success, eventmsqId %d, key 0x%x.\n", pCoreModule->moduleInfo.eventMsqId, coreEKey);
	if(pCoreModule->moduleInfo.eventMsqId == -1){
		pCoreModule->moduleInfo.eventMsqId = msgget(coreEKey, 0666 | IPC_CREAT);
		CMS_LOG(LL_INFO, "shmget success, eventmsqId %d, key 0x%x.\n", pCoreModule->moduleInfo.eventMsqId, coreEKey);
	}

	strcpy(pCoreModule->moduleInfo.moduleName, CMS_CORE);
	pCoreModule->moduleInfo.pid = getpid();
	pCoreModule->eventListOfModule = NULL;
	
	CMS_LOG(LL_INFO, "create module success. moduleName: %s,moduleMsqId:%d, eventMsqId: %d, pid: %d.\n",
		pCoreModule->moduleInfo.moduleName, pCoreModule->moduleInfo.moduleMsqId,
		pCoreModule->moduleInfo.eventMsqId, pCoreModule->moduleInfo.pid);
	
	/*inserst core module to module list*/
	pCurModuleList = (cms_moduleList_t *)calloc(1, sizeof(cms_moduleList_t));
	if(pCurModuleList == NULL){
		CMS_LOG(LL_ERROR, "core init fail, malloc module fail.\n");
		safe_free(pCoreModule);
		return -1;
	}
	pCurModuleList->module = pCoreModule;
	pCurModuleList->prev = NULL;
	pCurModuleList->next = NULL;

	INSERT_NODE(moduleList, pCurModuleList);
	

#ifdef CMS_SUPPORT_YL
	/*get preConfig partition & current backup partition*/
	if(libgc_sys_getBackupConfig(CMS_BACKUP_CONFIG_FILE) == 1){
		CMS_LOG(LL_ERROR|LL_SYSLOG, "get backup config file from backup parition fail.");
		cms_log_record("get configuration file form backup partition fail.");
	}
	if(libgc_sys_getPreConfig(CMS_PRE_CONFIG_FILE) == 1){
		CMS_LOG(LL_ERROR|LL_SYSLOG, "get pre config file from pre parition fail.");
	}
#endif

	/*get default xml by different country and different province or city*/
	defaultXmlPath = getPreDefaultXml();

	char logStr[128] = {0};
	sprintf(logStr, "get default xml by province-code is: %s, xml init start.", defaultXmlPath);
	cms_log_record(logStr);
	CMS_LOG(LL_PRINT|LL_SYSLOG, "%s", logStr);
	
	/*alloc share memory for xml*/
	cmsXmlCb = XMLSHMALLOC(defaultXmlPath);
	if (cmsXmlCb == NULL){
		cms_do_cmd("touch /tmp/LoadDefaultConfigFail");
		sprintf(cmdStr, "echo %s > /tmp/LoadDefaultConfigFail",defaultXmlPath);
		cms_do_cmd(cmdStr);
		CMS_LOG(LL_ERROR, "malloc xml share memory fail.\n");
		return -1;
	}
	cms_do_cmd("touch /tmp/LoadDefaultConfigSucc");
	sprintf(cmdStr, "echo %s > /tmp/LoadDefaultConfigSucc",defaultXmlPath);
	cms_do_cmd(cmdStr);
	
	/*alloc default xml shm*/
	cmsDefXmlCb = XMLSHM_DEFAULT_MALLOC(defaultXmlPath);
	if(cmsDefXmlCb == NULL)
		CMS_LOG(LL_ERROR, "xml shm with default xml malloc fail!!!\n");
	CMS_LOG(LL_PRINT|LL_SYSLOG, "cms_core init success.");

	return 0;
}

int main(int argc, char* argv[]){
	cmsMsgCb_t *pRecvMsg = NULL, *pReplyMsg = NULL;
	cmsMsg_header_t *pMsgHeader = NULL;
	cmsMsg_action_t *pAction = NULL;
	uint32_t status = 0;
	int actionNum = 0;
	int ret = -1;

    cmsSetLogLevel(NULL, CMS_CORE);

	log_enable_syslog();

	ret = cmsCore_Init();
	if(ret == -1){
		CMS_LOG(LL_ERROR, "cms_core init fail.\n");
		return -1;
	}

	while(1){
		CMS_LOG(LL_INFO, "cms_core--wait recv msg.\n");
		pRecvMsg = cms_recvMsg(0,0);
		if(pRecvMsg == NULL){
			CMS_LOG(LL_ERROR, "cms_core--recv msg is NULL.\n");
			continue;
		}else{
			CMS_LOG(LL_INFO, "msg received success, shmId %d, msgType 0x%x.\n", pRecvMsg->shmId, pRecvMsg->msgType);
		}

		
		pMsgHeader = cms_parseMsgHeader(pRecvMsg);
		if(DEBUG_LOG){
			CMS_LOG(LL_DEBUG, "srcId: %d, dtsId: %d, sessionId: %d, actNum: %d, flag: 0x%x.\n",
				pMsgHeader->srcModuleId, pMsgHeader->dstModuleId, pMsgHeader->sessionId, pMsgHeader->actionNum, pMsgHeader->flag);
		}

		actionNum = pMsgHeader->actionNum;
		if(pMsgHeader->dstModuleId == 0){
			if(pMsgHeader->flag & CMS_MSG_EVENT){ /*handle event notfiy*/
				CMS_LOG(LL_INFO, "cms_core--recv event reuest.\n");
				cmsCore_notify(pRecvMsg);

				cms_msgFree(pRecvMsg);
				continue;
				
			}else{ /*handle reg/unreg, subscribe/unsubscribe*/
				CMS_LOG(LL_INFO, "cms_core--recv msg, not msg_event, 0x%x.\n", pMsgHeader->flag);
				while(actionNum){
					pAction = cms_parseMsgAction(pRecvMsg);
					if(pAction == NULL){
						CMS_LOG(LL_ERROR, "cms_core--parse action fail.\n");
						return -1;
					}
					
					switch(pAction->action->type){
					case CMS_MSG_ACT_REGMODULE:
						CMS_LOG(LL_DEBUG, "cms_core--register module, flag 0x%x, msgtype: 0x%x.\n", pRecvMsg->header.flag,pRecvMsg->msgType);
						ret = cmsCore_regModule(pAction);
						if(ret == -1){
							status = CMS_STATUS_FAIL;
							CMS_LOG(LL_DEBUG,"cms_core--register module fail.\n");
						}else{
							status = CMS_STATUS_SUCCESS;
							CMS_LOG(LL_DEBUG,"cms_core--register module success.\n");
						}
				
						break;
					case CMS_MSG_ACT_UNREGMODULE:
						CMS_LOG(LL_DEBUG,"cms_core--unregister module.\n");
						ret = cmsCore_unregModule(pAction);
						if(ret == -1){
							status = CMS_STATUS_FAIL;
							CMS_LOG(LL_DEBUG,"cms_core--unregister module fail.\n");
						}else{
							status = CMS_STATUS_SUCCESS;
							CMS_LOG(LL_DEBUG,"cms_core--unregister module success.\n");
						}
						break;
					case CMS_MSG_ACT_SUBSCRIBEEVENT:
						CMS_LOG(LL_DEBUG,"cms_core--subscribe event.\n");
						ret = cmsCore_subscribeEvent(pAction->event, pMsgHeader->srcModuleId);
						if(ret == -1){
							status = CMS_STATUS_FAIL;
							CMS_LOG(LL_DEBUG,"cms_core--subscribeEvent fail.\n");
						}else{
							status = CMS_STATUS_SUCCESS;
							CMS_LOG(LL_DEBUG,"cms_core--subscribeEvent success.\n");
						}
						break;
					case CMS_MSG_ACT_UNSUBSCRIBEEVENT:
						CMS_LOG(LL_DEBUG,"cms_core--unsubscribe event.\n");
						ret = cmsCore_unSubscribeEvent(pAction->event, pMsgHeader->srcModuleId);
						if(ret == -1){
							status = CMS_STATUS_FAIL;
							CMS_LOG(LL_DEBUG,"cms_core--unsubscribeEvent fail.\n");
						}else{
							status = CMS_STATUS_SUCCESS;
							CMS_LOG(LL_DEBUG,"cms_core--unsubscribeEvent success.\n");
						}
						break;
					case CMS_MSG_ACT_GETMODULEID:
						CMS_LOG(LL_DEBUG,"cms_core--get module id, moduleName is %s.\n", pAction->module->moduleName);
						cms_moduleList_t *pSeekModule = NULL;
						pSeekModule = cmsCore_seekModuleByName(pAction->module->moduleName);
						if(pSeekModule){
							pAction->module->moduleMsqId = pSeekModule->module->moduleInfo.moduleMsqId;
							status = CMS_STATUS_SUCCESS;
							CMS_LOG(LL_DEBUG,"cms_core--get module id by search name success, moduleId is %d.\n", pAction->module->moduleMsqId);
						}else{
							status = CMS_STATUS_FAIL;
							CMS_LOG(LL_DEBUG,"cms_core--get module id by search name fail.\n");
						}
						break;
					case CMS_MSG_ACT_QUEUE_CLEAN:
						CMS_LOG(LL_ERROR, "msg queue full, please module check!!!\n");
						cmsCore_moduleCheck();
						break;
					case CMS_MSG_ACT_SET_LOG:
						ret = cmsSetLogLevel(pAction, CMS_CORE);
						status = ((ret == CMS_OK) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
						break;
					case CMS_MSG_ACT_GET_ALL_EVENT:
						cmsCore_printEvent(NULL);
						break;
					case CMS_MSG_ACT_GET_APP_EVENT:
						cmsCore_printEvent(pAction->file->fileName);
						break;
					default:
						CMS_LOG(LL_DEBUG,"action for test, action type 0x%x.\n", pAction->action->type);
	
						if(pAction->action->type == CMS_MSG_ACT_GETOBJ){
							CMS_LOG(LL_INFO, "objId %d, ia %"PRIx64", shm %d\n", pAction->object->objOffset.id,
								pAction->object->objOffset.IA, pAction->object->objOffset.shmId);

							break;
						}
					
						break;
					}

					actionNum--;
				}
		
				pReplyMsg = cms_createReplyMsg(pRecvMsg, status);

				if(pReplyMsg != NULL)
					CMS_LOG(LL_DEBUG, "recv msgtype: 0x%x, pReply msgtype: 0x%x, flag 0x%x\n",
						pRecvMsg->msgType, pReplyMsg->msgType,pReplyMsg->header.flag);
			}
			

			/*send reponse*/
			if(pReplyMsg != NULL){
				ret = cms_sendMsg(pReplyMsg, pMsgHeader->srcModuleId);
				if(ret == -1){
					CMS_LOG(LL_ERROR,"cms_core--send reply msg fail.\n");
					pReplyMsg->msgType &=  ~CMS_MSG_SEND;
					pReplyMsg->msgType |=  CMS_MSG_RECV;
					while(pReplyMsg->next){
						pReplyMsg->next->msgType &=  ~CMS_MSG_SEND;
						pReplyMsg->next->msgType |=  CMS_MSG_RECV;
						pReplyMsg = pReplyMsg->next;
					}
				}else{
					CMS_LOG(LL_DEBUG,"cms_core--send reply msg success.\n");
				}
				cms_msgFree(pReplyMsg);
			}else{
				CMS_LOG(LL_ERROR,"cms_core--create reply msg fail.\n");
			}
			cms_msgFree(pRecvMsg);
			
		}else{
			ret = cmsCore_forwardMsg(pRecvMsg, pMsgHeader->dstModuleId);
			if(ret < 0)
				CMS_LOG(LL_ERROR,"cms_core--forward msg fail.\n");
		}
		
		cmsCore_printModuleList();
		cmsCore_printEventList();

	}
	
	XMLSHMDESTORY(cmsXmlCb);
	XMLSHM_DEFAULT_DESTORY(cmsDefXmlCb);
	return 0;
}
